import cgi
import datetime
from utils import *
from table import Candidate 
from google.appengine.ext import db
from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext.webapp.util import login_required


SIZE_LIMIT = 10**7
fixed_spaces = """
                &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
                &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
               """
NOT_STARTED = -1
STARTED = 0
ENDED = 1

def next_qno (cand):
    if cand.state == len(cand.group) or cand.state == -2:
        return "done"
    elif cand.qnos[cand.state] == -1 and cand.state+1 < len (cand.qnos):
        return str(cand.qnos[cand.state+1])
    else:
        return str(cand.qnos[cand.state])
        
class BackwardHandler(webapp.RequestHandler):

    def post(self):
        cand = get_candidate()
        qnos_done = cand.state-1        
        if qnos_done < 0:
            pass
        else:    
            while qnos_done-1 > -1 and cand.group[qnos_done-1] == cand.group[qnos_done]:
                qnos_done -= 1
            cand.state = qnos_done
            cand.put()                    
        self.redirect('/exam?q=%s'%next_qno(cand))

class ForwardHandler(webapp.RequestHandler):

    def post(self):
        cand = get_candidate()
        qnos_done = cand.state
        while qnos_done+1 < len(cand.group) and cand.group[qnos_done+1] == cand.group[qnos_done]:
            qnos_done += 1            
        if cand.state + 1 < len(cand.group):
            cand.state = qnos_done+1
            cand.put()
        self.redirect('/exam?q=%s'%next_qno(cand))
         

class MainHandler(webapp.RequestHandler):

    @login_required
    def get(self):	  
        wr = self.response.out.write
        user = users.get_current_user()
        cand = get_candidate()
        if cand :
            if cand.state != -2: 
                time_state = get_cand_time_status (cand)
                if time_state == NOT_STARTED:
                    sec = (cand.test_start_time-datetime.datetime(2008,10,11).utcnow ()).seconds
                    days = (cand.test_start_time-datetime.datetime(2008,10,11).utcnow ()).days
                    wr("<html><body onload=startTime(%d,%d)>"%(sec,days))
                elif time_state == STARTED:
                    sec = (cand.test_end_time-datetime.datetime(2008,10,11).utcnow ()).seconds
                    days = (cand.test_end_time-datetime.datetime(2008,10,11).utcnow ()).days
                    wr("<html><body onload=startTime(%d,%d)>"%(sec,days))
                else:
                    wr("<html><body>")

                wr("""<div align=center><h2>Online Test</h2></div>""")

                wr("""<script type="text/javascript">
                                            /*function verify()
                                            {
                                                return confirm ("Are you sure you want to submit?");
                                            }
                                            */
                                            function startTime(sec,days)
                                            {
                                            if ( sec != 0 ) {
                                                m = Math.floor(sec/60);
                                                s = sec%60;
                                                h = Math.floor(m/60);
                                                m = m%60;
                                                d = days;
                                                h = h%24; 
                                             } else {    
                                                s -= 1;
                                                if ( s < 0 ) {
                                                  m -= 1;
                                                  s = 59;
                                                  if ( m < 0 ) {
                                                    h -= 1;
                                                    m = 59;
                                                    if ( h < 0 ) {
                                                        d -= 1;
                                                        h = 23;
                                                        if ( d < 0 )  {
                                                            window.location='/exam';
                                                            return; 
                                                        }
                                                    }
                                                  }
                                                }
                                             }
                                            // add a zero in front of numbers<10
                                            h1=checkTime(h);
                                            m1=checkTime(m);
                                            s1=checkTime(s);
                                            txt.innerHTML = d +" Days " + h1 + ":" + m1 + ":" + s1
                                            t=setTimeout('startTime( 0 )',1000);
                                            }
                                            function checkTime(i)  {
                                             if (i<10) {
                                              i="0" + i;
                                             }
                                             return i;
                                            }
                                            </script>""")
                wr("<h1><div id='txt' align='right'></div></h1><br/>")
                #PRESENT THE TEST

                if time_state == NOT_STARTED:
                    self.response.out.write("Test hasn't started yet.!Please, %s stand by for the test to start<br/>"%user.nickname())
                    url = users.create_logout_url(self.request.uri)
                    self.response.out.write("<br><a href=%s>Logout</a>"%(url))
                elif time_state == ENDED:
                    self.response.out.write("Test timings are up.You will be informed of the results shortly.<br/>Thanks %s for taking up the test"%user.nickname())
                    url = users.create_logout_url(self.request.uri)
                    self.response.out.write("<br><a href=%s>Logout</a>"%(url))
                else:
                    wr("""<form action='/exam' method = 'POST'>""")                   
                    try:
                        curr_q = self.request.query_string
                        if curr_q.strip().startswith("q="):                    
                            curr_q = int (curr_q [2:])
                            if curr_q == -1:
                                raise
                            #Invalid input will cause an
                            #exception here and will be 
                            #handled.
                            curr_off = cand.qnos.index (curr_q)
                            while curr_off-1 > -1 and cand.group[curr_off-1] == cand.group[curr_off]:
                                curr_off -= 1
                            cand.state = curr_off
                    except:
                        pass
                    loopctr = 0
                    qns_done = cand.state
                    if qns_done == -1:
                        cand.state = 0
                        cand.put()
                        qns_done = 0
                    if qns_done == len(cand.group):
                        wr("""
                            You are done with the test, Click Submit to complete your test, or 
                            click back if you would<br\> wish to change any of the answers
                          """)
                    else:    
                        while True:
                            loopctr += 1                            
                            qoffset  = cand.qoffsets[qns_done]
                            questions = cand.questions[qoffset:]
                            #BEGIN OF IF's
                            if cand.qtype[qns_done] == 'CODE':
                                quest = unquote_html(questions[0])

                                wr("""
                                <h3>Below is a CODE Question. <br\>Read the below question carefully and design a program to solve the problem.
                                Run the program for the given input set and paste the output in the space given below. 
                                Also paste your source code in the appropriate area.
                                <br\>Answers without source code will not be considered for evaluation.</h3>
                                """)

                                wr ("""
                                    <p><div> Question# %d of %d%s
                                    <b>Marks = %d</b><br/> %s</div><br/></p>"""
                                        %(cand.qnos[qns_done],
                                        cand.total_qs,
                                        fixed_spaces,
                                        cand.prob_max_mark[qns_done],
                                        quest)
                                    )
                                
                                wr (""" 
                                    Input cases:<br/><div><textarea rows=10 cols=80 READONLY>%(input)s</textarea>
                                    <div><label for=%(op_name)s>Paste the output below in the exact format</label></div>
                                    <div><textarea name=%(op_name)s rows=10 cols=80>%(op_ans)s</textarea><br/></div>
                                    <br/><br/>
                                    <div><label for=%(sc_name)s>Paste the Source code below</label></div>
                                    <div><textarea name=%(sc_name)s rows=10 cols=80>%(sc_ans)s</textarea><br/></div>
                                   """ %{
                                        'input': questions[1], 
                                        'op_name':'op'+str(loopctr), 
                                        'op_ans':cand.given_ans[cand.goffsets[qns_done]], 
                                        'sc_name':'sc'+str(loopctr), 
                                        'sc_ans':cand.given_ans[cand.goffsets[qns_done]+1]
                                        }
                                    )

                            if cand.qtype[qns_done] == 'FIBQ':
                                quest = unquote_html(questions[0])
                                wr("""
                                    <h3>Below is a Fill in the blank question. 
                                    It is automatically evaluated, 
                                    so just fill in the exact answer in the text box below,This is case-insensitive</h3>
                                """)

                                wr (
                                    """<p><div> Question# %d of %d%s
                                        <b>Marks = %d</b><br/> %s</div><br/></p>"""
                                        %(cand.qnos[qns_done],
                                        cand.total_qs,
                                        fixed_spaces,
                                        cand.prob_max_mark[qns_done],
                                        quest)
                                    )

                                wr(
                                    '<div><textarea rows=5 cols=80 name=%s>%s</textarea></div>'%(
                                        'fibq'+str(loopctr),
                                        cand.given_ans[cand.goffsets[qns_done]])
                                )

                            if cand.qtype[qns_done] == 'PASSAGE':
                                quest = unquote_html (questions[0])
                                noofquest = int(questions[1])

                                wr(
                                    """<h3><p>Below is a passage question. 
                                    Read the passage and answer the %d questions to follow</p></h3>"""%noofquest
                                )

                                wr(
                                    """<p><div> Question# %s%s
                                       <b> Total Marks = %d</b><br/> %s</div><br/></p>"""
                                       %('PASSAGE',
                                        fixed_spaces, 
                                        reduce(lambda a,b: a+b, cand.prob_max_mark[qns_done+1:qns_done+noofquest+1]),
                                        quest)                                
                                )

                            if cand.qtype[qns_done] == 'MCQRB' or cand.qtype[qns_done] == 'MCQCB':
                                quest = unquote_html (questions[0])
                                noofoptn = int(questions[1])
                                optns = questions[2:2+noofoptn]
                                wr (
                                    """<p><div> Question# %d of %d%s
                                    <b>Marks = %d</b><br/> %s</div><br/></p>"""
                                        %(cand.qnos[qns_done],
                                        cand.total_qs,
                                        fixed_spaces,
                                        cand.prob_max_mark[qns_done],
                                        quest)
                                )

                                for optn in enumerate(optns):
                                    if cand.qtype[qns_done] == 'MCQRB':
                                        if str(optn[0]+1) in cand.given_ans[cand.goffsets[qns_done]]:
                                            wr(
                                                '<div><input name=%s type="radio" value=%d tabindex=%d checked>%s</input></div><br/>'
                                                    %('rb'+str(loopctr),
                                                    optn[0]+1,
                                                    optn[0]+1,
                                                    optn[1])
                                            )
                                        else:                                        
                                            wr(
                                                '<div><input name=%s type="radio" value=%d tabindex=%d>%s</input></div><br/>'
                                                    %('rb'+str(loopctr),
                                                    optn[0]+1,
                                                    optn[0]+1,
                                                    optn[1])
                                            )

                                    if cand.qtype[qns_done] == 'MCQCB':                                    
                                        if str(optn[0]+1) in cand.given_ans[cand.goffsets[qns_done]]:
                                            wr(
                                                '<div><input name=%s type="checkbox" value=%d tabindex=%d checked>%s</input></div><br/>'
                                                    %('cb'+str(optn[0]+1)+str(loopctr),
                                                    optn[0]+1,
                                                    optn[0]+1,
                                                    optn[1])
                                            )
                                        else:                                        
                                            wr(
                                                '<div><input name=%s type="checkbox" value=%d tabindex=%d>%s</input></div><br/>'
                                                    %('cb'+str(optn[0]+1)+str(loopctr),
                                                    optn[0]+1,
                                                    optn[0]+1,
                                                    optn[1])
                                            )
                                if cand.qtype[qns_done] == 'MCQCB':                                    
                                        wr(
                                            '<div><input name=%s type="hidden" value="%d"/></div>'
                                                %('options'+str(loopctr),
                                                len(optns))
                                        )
                            #END OF IF's
                            if qns_done+1 == len(cand.group) or cand.group[qns_done] != cand.group[qns_done+1]:
                                break
                            qns_done += 1
                    wr('<div><input name="qns" type="hidden" value="%d"/></div>'%(qns_done))                                                        
                    wr("""<div><input type="submit" value="submit"/></div>
                          </form>""")
                    wr("""<span><form action='/back' method = 'POST'>
                           <div><input type="submit" value="Move Back Without Submitting the Answers"/></div></form> """)
                    wr("""<form action='/forward' method = 'POST'>
                          <div><input type="submit" value="Move Forward Without Submitting the Answers"/></div></form></span> """)
                wr('</body></html>')        
            else:
                wr('<html><body>')
                wr("""Thanks for taking the test<br/>The results will be shortly announced<br/>""")
                url = users.create_logout_url(self.request.uri)
                wr("<a href=%s>Logout</a>"%(url))
                wr('</body></html>')
        else:            
            #TELL HE IS NOT AUTHORISED BY THE COLLEGE TO TAKE UP THE TEST
            wr('<html><body>')
            wr("<div align=center><h2>Online Test</h2></div>")
            wr(
                """%s, Your email id is not in the list of authorized email ids"""%user.nickname()
            )
            url = users.create_logout_url(self.request.uri)
            wr("<a href=%s>Logout</a>"%(url))
            wr('</body></html>')


    def post(self):
        cand = get_candidate()
        loop_ctr = 0
        qns_done = cand.state        
        if qns_done == len(cand.group):
            cand.state = -2
        else:
            while True:
                loop_ctr += 1                
                                                    #########EVALUATION OF ANSWERS AND SCORING###############

                #SINCE WE DONT ADD EXPECTED AND GIVEN ANSWER FOR PASSAGE QUESTIONS
                #WE DONT CHECK THEIR CORRECTNESS HERE
                if cand.qtype[qns_done] == 'CODE':
                    try:
                        user_ans_op = self.request.get('op'+str(loop_ctr))
                        user_ans_sc = self.request.get('sc'+str(loop_ctr))                       
                    except Exception,e:
                        user_ans_op = ''
                        user_ans_sc = ''
                    exp_ans = cand.exp_ans[cand.goffsets[qns_done]]
                    cand.given_ans[cand.goffsets[qns_done]] = db.Text(user_ans_op)
                    cand.given_ans[cand.goffsets[qns_done]+1] = db.Text(user_ans_sc)
                    cand.has_answered[qns_done] = True
                    delim = cand.questions[cand.qoffsets[qns_done]+2]
                    exp_ans_split = exp_ans.strip().replace('\r\n','\n').split(delim)
                    user_ans_split = user_ans_op.strip().replace('\r\n','\n')[:SIZE_LIMIT].split(delim)
                    noofans = len(exp_ans_split)
                    noofcor = 0 
                    for e,u in zip(exp_ans_split,user_ans_split):
                        if e.strip()==u.strip():
                            noofcor += 1
                    cand.total_stud_mark -= cand.prob_stud_mark[qns_done]
                    try:
                        cand.prob_stud_mark[qns_done] = int(cand.prob_max_mark[qns_done]*(float(noofcor)/noofans))
                    except Exception,e:
                        cand.prob_stud_mark[qns_done] = 0L
                    cand.total_stud_mark += cand.prob_stud_mark[qns_done]
                if cand.qtype[qns_done] == 'FIBQ':
                    user_ans = self.request.get('fibq'+str(loop_ctr)).strip()
                    exp_ans = cand.exp_ans[cand.goffsets[qns_done]]
                    cand.given_ans[cand.goffsets[qns_done]] = db.Text(user_ans)
                    cand.has_answered[qns_done] = True
                    cand.total_stud_mark -= cand.prob_stud_mark[qns_done]
                    if user_ans.lower() == exp_ans.lower():
                        cand.prob_stud_mark[qns_done] = cand.prob_max_mark[qns_done]
                    else:
                        cand.prob_stud_mark[qns_done] = 0L                   
                    cand.total_stud_mark += cand.prob_stud_mark[qns_done]
                if cand.qtype[qns_done] == 'MCQRB':
                    try:
                        user_ans = self.request.get('rb'+str(loop_ctr))
                    except Exception,e:
                        user_ans = '0'
                    exp_ans = cand.exp_ans[cand.goffsets[qns_done]]
                    cand.given_ans[cand.goffsets[qns_done]] = db.Text(user_ans)
                    cand.has_answered[qns_done] = True
                    cand.total_stud_mark -= cand.prob_stud_mark[qns_done]
                    if user_ans == exp_ans:
                        cand.prob_stud_mark[qns_done] = cand.prob_max_mark[qns_done]
                    else:
                        cand.prob_stud_mark[qns_done] = 0L
                    cand.total_stud_mark += cand.prob_stud_mark[qns_done]
                if cand.qtype[qns_done] == 'MCQCB':
                    optns = int(self.request.get('options'+str(loop_ctr)))
                    user_ans=[]
                    for x in range(optns):
                        try:
                            ans = self.request.get('cb'+str(x+1)+str(loop_ctr))
                            if ans:
                                user_ans.append(ans)
                        except Exception,e:
                            pass
                    exp_ans = cand.exp_ans[cand.goffsets[qns_done]].split(",")
                    if len(user_ans):
                        cand.given_ans[cand.goffsets[qns_done]] = db.Text(reduce(lambda a,b: a+','+b, user_ans))
                    correct = True
                    cand.has_answered[qns_done] = True
                    if len(user_ans)==len(exp_ans):
                        for u,e in zip(user_ans,exp_ans):
                            if u != e:
                                correct = False
                    else:
                        correct = False
                    cand.total_stud_mark -= cand.prob_stud_mark[qns_done]
                    if correct:                    
                        cand.prob_stud_mark[qns_done] = cand.prob_max_mark[qns_done]
                    else:
                        cand.prob_stud_mark[qns_done] = 0L 
                    cand.total_stud_mark += cand.prob_stud_mark[qns_done]
                if qns_done+1 == len(cand.group) or cand.group[qns_done] != cand.group[qns_done+1]:
                    break                                    
                qns_done += 1
        qns_done = int(self.request.get('qns'))
        #We add 1 to move to the next question
        cand.state= qns_done+1 
        if cand.state == len(cand.group)+1:
            cand.state = -2
        cand.put()

        self.redirect('/exam?q=%s'%next_qno(cand))

application = webapp.WSGIApplication([('/exam', MainHandler),
                                      ('/back', BackwardHandler),
                                      ('/forward', ForwardHandler)],
                                       debug=True)

def main():
    run_wsgi_app(application)

if __name__ == '__main__':
  main()    
